Skip to content

[FEAT] 오늘 화면 TodayTodoCard 컴포넌트 구현#106

Merged
ehye1 merged 31 commits into
developfrom
feat/web/101-today-todo-card
Jul 10, 2026
Merged

[FEAT] 오늘 화면 TodayTodoCard 컴포넌트 구현#106
ehye1 merged 31 commits into
developfrom
feat/web/101-today-todo-card

Conversation

@ehye1

@ehye1 ehye1 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

ISSUE 🔗

close #101



What is this PR? 🔍

TodayTodoCard 컴포넌트 구현

4가지 variant를 2개의 boolean prop으로 처리
isDone × isDimmed 조합으로 카드 상태를 커버하며, 스타일은 Record 패턴으로 관리합니다.

const CARD_STYLE = {
  active: { card: "bg-white", title: "text-timo-gray-900", ... },
  done:   { card: "bg-timo-gray-200", title: "text-timo-gray-700", ... },
}

hover 시 흐려짐 해제
isDone=true이면 카드가 흐려지지만, 마우스를 올리면 즉시 원래 상태로 복귀합니다. 체크박스는 항상 클릭 가능합니다.

const isDimmed = isDone && !isHovered

toolbar props 그룹화
날짜, 시간, 우선순위 등 메타 정보를 flat props 대신 toolbar 객체로 묶어 호출부를 간결하게 했습니다.

<TodayTodoCard toolbar={{ date: "26.07.01", priority: "urgent", memo: true }} />

isDraggable 제거
드래그 핸들은 별도 prop 없이 항상 렌더링하는 방향으로 결정하여 isDraggable prop을 제거했습니다.

dimmed 상태 아이콘 처리
isDimmed=true일 때 toolbar 아이콘 전체가 disable 버전으로 전환됩니다. CreateTodoToolbarisDimmed prop을 그대로 전달해 아이콘 상태를 결정합니다.

아이콘 피커 연동 구조 준비
icon?: ReactNode + onIconClick?: () => void로 추후 피커 구현 시 연동 가능하도록 열어뒀습니다.

CreateTodoToolbar 컴포넌트 구현

피그마 스펙에 맞춰 CreateTodoToolbar를 별도 컴포넌트로 분리하고, TodayTodoCard의 인라인 toolbar를 교체했습니다.

  • isDimmed 상태에서 모든 toolbar 아이콘을 disable 버전으로 전환
  • PriorityIcon 버튼을 피그마 스펙(22×22)에 맞게 size-[22px] flex items-center justify-center 적용
  • time 텍스트 프레임 width w-9(36px) 고정 — 시간 변경 시 toolbar 너비 흔들림 방지
  • date, time, priority, memo, onDateClick~onMemoClick에서 불필요한 ? 제거 — 항상 제공되는 props를 타입 수준에서 명시적으로 표현했습니다

Design System 수정

  • HamburgerGray 아이콘 추가 — done 상태 드래그 핸들용
  • PriorityIcon Disable 색상 gray-500gray-700
  • TagIcon 좌우 padding 6.5px10px (피그마 스펙)
  • Calendar SVG 3종 clipPath 오프셋 수정 (translate(2, 2.5)translate(2, 2)) — Figma export 버그로 달력 아이콘이 0.5px 아래로 내려가 있던 문제 수정

체크박스 상태 관리 — uncontrolled 패턴 채택

TodayTodoCard는 모달에서 생성 버튼을 눌렀을 때 추가되는 구조입니다. 실제 목록 관리는 추후 Zustand store에서 담당할 예정이어서, 지금 단계에서는 isDonesubTodos를 컴포넌트 내부 state로 관리하는 uncontrolled 패턴을 택했습니다.

const [internalIsDone, setInternalIsDone] = useState(isDone);
const [internalSubTodos, setInternalSubTodos] = useState(subTodos ?? []);
  • 체크박스 토글은 카드가 자체적으로 처리
  • onCheck / onSubTodoCheck 콜백은 옵셔널 — Zustand 연결 시 해당 콜백을 꽂으면 부모에게도 알림이 전달되는 구조

isDone 자동 정지 시 부모 알림

타이머가 돌아가는 중(isPlaying=true)에 할 일을 완료 처리하면 타이머가 자동으로 멈추고, onPlay?.() 를 호출해 부모(추후 전역 store)에게 정지 사실을 알립니다.

useEffect(() => {
  if (internalIsDone && isPlaying) {
    setIsPlaying(false);
    onPlay?.();
  }
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, [internalIsDone]);

deps를 [internalIsDone] 하나만 두는 이유: internalIsDone이 바뀌는 시점의 isPlaying 값을 참조하는 게 의도된 동작입니다. Zustand + 실제 타이머 연결 시 이 effect는 전면 교체될 예정입니다.

개발 확인용 mock 데이터

page.tsx는 Server Component라 직접 state를 가질 수 없고, 별도 client wrapper를 만드는 것보다 uncontrolled 패턴으로 카드 자체가 상태를 갖는 게 현 단계에서 더 자연스럽다고 판단했습니다. mock 데이터는 _mocks/today-todo-mock.ts로 분리해두었으며, API 연결 후 제거할 예정입니다.

// TODO: API 연결 후 mock 데이터 제거
import { todayTodoMock } from "./_mocks/today-todo-mock";



To Reviewers

  • isDimmed = isDone && !isHovered 패턴으로 hover 시 흐려짐 해제를 구현했습니다. 클릭 시 hover 상태이므로 마우스가 카드를 벗어나야 흐려지는 건 의도된 동작입니다.
  • 아이콘 피커는 추후 구현 예정으로, 현재는 icon / onIconClick prop만 열어뒀습니다.
  • CreateTodoToolbar는 현재 각 버튼 클릭 시 모달 연결이 남아 있습니다. 이슈를 새로 파서 후속 PR에서 처리할 예정입니다.
  • 체크박스·subTodo 상태는 현재 카드 내부에서 관리(uncontrolled)하며, Zustand 연결 시 onCheck / onSubTodoCheck 콜백을 통해 외부 store와 연결됩니다.



Screenshot 📷

Timo.-.Chrome.2026-07-07.03-07-16.mp4

Test Checklist ✔

  • 상위 체크박스 클릭 → 카드 흐려짐, 마우스 올리면 복귀
  • 하위 체크박스 개별 토글 동작
  • 툴바 아이콘 done 상태에서 disable 버전으로 전환
  • 제목 한글 20자·영어 30자 초과 시 말줄임표 처리
  • 타이머 재생 중 완료 처리 시 자동 정지 확인

ehye1 and others added 2 commits July 7, 2026 02:25
- isDone + isDraggable 조합으로 4가지 variant 처리 (Record 패턴)
- Checkbox, PlayButton 디자인 시스템 컴포넌트 재사용
- icon/onIconClick prop으로 아이콘 피커 연동 구조 준비
- HamburgerGray 아이콘 추가 (done 상태 핸들)
- PriorityIcon Disable 색상 gray-500 -> gray-700 수정
- Calendar SVG 계열 clipPath 오프셋 0.5px 수정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- toolbar 관련 props를 TodayTodoCardToolbar 객체로 묶음
- isDimmed = isDone && !isHovered 로 hover시 흐려짐 해제 구현
- 체크박스 disabled 제거 (항상 클릭 가능)
- icon 조건 수정: icon && (onIconClick만 있을 때 빈 버튼 렌더 방지)
- page.tsx 테스트 코드 제거

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 10, 2026 5:34pm

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

오늘 화면에 투두 카드와 툴바가 연결되었고, 카드 상태 관리용 컨테이너와 목데이터가 추가되었습니다. 태그/우선순위 아이콘의 disable variant도 디자인시스템에 반영되었습니다.

Changes

Today Todo UI

Layer / File(s) Summary
아이콘 variant와 스토리 조정
packages/timo-design-system/src/components/priority/priority-icon/PriorityIcon.tsx, packages/timo-design-system/src/components/button/modal-button/ModalButton.stories.tsx, packages/timo-design-system/src/components/tag/tag-icon/TagIcon.tsx, packages/timo-design-system/src/components/tag/tag-icon/TagIcon.stories.tsx
PriorityIcon의 Disable 배경색이 바뀌고, TagIcondisable variant와 대응 텍스트 색상 매핑이 추가되며, 관련 스토리와 ModalButton 스토리 폭이 함께 조정됨.
CreateTodoToolbar 구현
apps/timo-web/components/CreateTodoToolbar.tsx
날짜/시간/우선순위/태그/메모/반복/삭제 버튼이 값과 activeItem에 따라 아이콘·텍스트·variant를 바꾸도록 CreateTodoToolbarProps와 컴포넌트가 추가됨.
TodayTodoCard 상태와 렌더링
apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx, apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoCardContainer.tsx
카드의 hover/done/play/subTodo 상태와 이벤트 핸들러가 추가되고, 카드 본문·서브투두·툴바가 현재 상태에 맞게 렌더링되도록 연결됨.
TodayPage와 목데이터 연결
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/page.tsx, apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_mocks/today-todo-mock.ts
TodayPage가 카드 컨테이너를 렌더링하도록 바뀌고, 단일 카드 목과 여러 카드 목 데이터가 추가됨.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TodayPage
  participant TodayTodoCardContainer
  participant TodayTodoCard
  participant CreateTodoToolbar

  User->>TodayPage: 오늘 화면 진입
  TodayPage->>TodayTodoCardContainer: todayTodoMock 전달
  TodayTodoCardContainer->>TodayTodoCard: 상태와 이벤트 핸들러 전달
  TodayTodoCard->>CreateTodoToolbar: date/time/priority/tag/memo/repeat/delete 전달
  User->>TodayTodoCardContainer: 체크/재생/서브투두 조작
  TodayTodoCardContainer->>TodayTodoCardContainer: 내부 상태 갱신
Loading

Possibly related PRs

Suggested labels: \⏰ Timo-web`, `⌚ Timo-Design-system`, `♦️ 민아``

Suggested reviewers: \yumin-kim2`, `jjangminii``

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning ModalButton.stories의 폭 클래스 변경은 TodayTodoCard 구현과 직접 관련이 없어 범위를 벗어납니다. 해당 story 변경은 별도 PR로 분리하거나 원래 폭 설정으로 되돌린 뒤, 이슈 범위와 맞는 변경만 남기세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 이슈의 핵심인 TodayTodoCard 4가지 variant와 툴바·서브투두 구현이 반영되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed 오늘 화면의 TodayTodoCard 컴포넌트 구현과 관련된 제목으로, 변경의 핵심을 잘 요약합니다.
Description check ✅ Passed 설명은 TodayTodoCard와 CreateTodoToolbar 구현, 디자인 시스템 수정 등 실제 변경 내용과 일치합니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/web/101-today-todo-card

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ehye1 ehye1 changed the title feat(web): TodayTodoCard 컴포넌트 구현 (#101) [FEAT] TodayTodoCard 컴포넌트 구현 Jul 6, 2026
@github-actions github-actions Bot added the ✨ Feature 새로운 기능(기능성) 구현 label Jul 6, 2026
@ehye1 ehye1 changed the title [FEAT] TodayTodoCard 컴포넌트 구현 [FEAT] 오늘 화면 TodayTodoCard 컴포넌트 구현 Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Storybook Preview

항목 링크
Storybook 열기
Chromatic 빌드 확인

마지막 업데이트: 2026-07-10 17:35 UTC

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale]/home 71.65 kB 🟡 277.47 kB
/[locale]/today 55.05 kB 🟡 260.87 kB
/[locale]/focus 51.90 kB 🟡 257.72 kB
/[locale]/settings/account 0 B 🟡 205.81 kB
/[locale]/settings 0 B 🟡 205.81 kB
/[locale]/settings/policy 0 B 🟡 205.81 kB
/[locale]/statistics 49.82 kB 🟡 255.63 kB
/[locale]/[...rest] 0 B 🟡 205.81 kB
/[locale]/onboarding 107.39 kB 🟡 313.21 kB
/[locale] 0 B 🟡 205.81 kB

공유 번들: 205.81 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🟡 70 🟢 96 🔴 14.0s 🟢 0.000 🟡 233ms
/en/today 🟡 73 🟡 93 🔴 13.8s 🟢 0.000 🟢 173ms
/en/focus 🟡 73 🟡 91 🔴 13.7s 🟢 0.000 🟢 132ms
/en/statistics 🟡 74 🟢 95 🔴 13.7s 🟢 0.000 🟢 146ms

Perf ≥ 70 / A11y ≥ 85 목표
LCP 🟢 < 2.5s 🟡 < 4s 🔴 ≥ 4s  |  CLS 🟢 < 0.1 🟡 < 0.25 🔴 ≥ 0.25  |  TBT 🟢 < 200ms 🟡 < 600ms 🔴 ≥ 600ms

Image Optimization — timo-web

public/ 디렉토리에 이미지가 없습니다.

측정 커밋: 3c90852

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/timo-web/app/today/_components/TodayTodoCard.tsx`:
- Line 30: The type alias for the priority union in TodayTodoCard should follow
the team convention by using a Types suffix. Rename the `Priority` alias defined
from `ComponentProps<typeof PriorityIcon>["priority"]` to a `Types`-suffixed
name, and update all references in the same component such as the `priority?:
...` prop and `toolbar.priority` usage to match the new alias name.
- Around line 143-157: 서브투두 렌더링 블록에서 `div`로 감싼 목록을 시맨틱 리스트로 바꿔 접근성을 개선하세요.
`TodayTodoCard`의 `subTodos.map` 구간과 각 항목의 컨테이너를 `ul`/`li` 구조로 변경하고, 기존
`flex`/`gap` 스타일은 유지하면 됩니다. `Checkbox`, `sub.id`, `sub.text`, `onSubTodoCheck`
동작은 그대로 두고, 목록 의미가 전달되도록 리스트 마크업만 정리하세요.
- Around line 161-184: The date/time UI in TodayTodoCard is rendered as button
elements without any actual action, so replace the toolbar date/time buttons
with non-interactive text elements unless there is a real click behavior. Update
the toolbar rendering in TodayTodoCard to use span/div for the date and time
display, or, if interaction is intended, add and wire up onDateClick/onTimeClick
props so the button elements in the toolbar have a concrete handler.
- Line 1: TodayTodoCard still has client-only hover state in a _components_ UI
file, which breaks the pure presentational layer rule. Move the isDimmed
behavior into the _containers_ layer or replace the stateful hover logic with
CSS-based group-hover/group-focus-within handling, then remove the use client
directive from TodayTodoCard so it remains a pure props-only component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d69c418b-cbfb-4fcd-b021-8af8eb219b4c

📥 Commits

Reviewing files that changed from the base of the PR and between e12b5af and f270c93.

⛔ Files ignored due to path filters (5)
  • packages/timo-design-system/src/icons/source/calendar-blue.svg is excluded by !**/*.svg
  • packages/timo-design-system/src/icons/source/calendar-disable.svg is excluded by !**/*.svg
  • packages/timo-design-system/src/icons/source/calendar-on.svg is excluded by !**/*.svg
  • packages/timo-design-system/src/icons/source/hamburger-gray.svg is excluded by !**/*.svg
  • packages/timo-design-system/src/icons/source/hamburger.svg is excluded by !**/*.svg
📒 Files selected for processing (3)
  • apps/timo-web/app/today/_components/.gitkeep
  • apps/timo-web/app/today/_components/TodayTodoCard.tsx
  • packages/timo-design-system/src/components/priority/priority-icon/PriorityIcon.tsx

Comment thread apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx Outdated
Comment thread apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx Outdated
Comment thread apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx Outdated
Comment thread apps/timo-web/app/today/_components/TodayTodoCard.tsx Outdated

@yumin-kim2 yumin-kim2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아이콘/텍스트 반복되는 UI 요소(날짜, 시간, 태그 등)를 비슷한 패턴으로 통일감 있게 작성하셔서, 코드를 읽을 때 패턴만 한 번 이해하면 나머지는 쉽게 따라 읽을 수 있었습니다 👍
코멘트 달았는데 확인해주세요 수고하셨써요~~~~!!!!✨

Comment thread apps/timo-web/app/today/_components/TodayTodoCard.tsx Outdated
ehye1 added 4 commits July 7, 2026 21:22
- CreateTodoToolbar 컴포넌트를 구현했습니다
- TodayTodoCard 인라인 toolbar를 CreateTodoToolbar로 교체했습니다
- isDimmed 상태에서 모든 toolbar 아이템을 disable 처리했습니다
- 한글 20자·영어 30자 기준 truncateTitle 함수를 적용했습니다
- 미사용 CARD_STYLE meta 필드를 제거했습니다
- TodayPage에 테스트 데이터를 추가했습니다
- 좌우 padding을 6.5px에서 10px로 수정했습니다
- w-[36px]을 Tailwind 표준 클래스 w-9으로 변경했습니다

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/timo-web/app/today/_components/TodayTodoCard.tsx`:
- Around line 175-186: CreateTodoToolbar is rendered with only the delete action
wired, so the other toolbar controls are visually clickable but do nothing. In
TodayTodoCard, pass through the missing handlers from the parent state/props for
onDateClick, onTimeClick, onPriorityClick, onTagClick, onMemoClick, and
onRepeatClick alongside the existing toolbar values, using the CreateTodoToolbar
component as the reference point.
- Line 18: The import in TodayTodoCard should use the existing `@/` alias instead
of a brittle relative path. Update the CreateTodoToolbar import in TodayTodoCard
to reference the alias form so it stays stable if the component moves, and keep
the rest of the component unchanged.
- Around line 24-39: The truncateTitle function is trimming one character too
early at the exact display limit because the boundary check uses a non-strict
comparison. Update the truncation condition inside truncateTitle so titles at
the exact Korean/other character thresholds are preserved, and only truncate
when the limit is actually exceeded; keep the fix localized to the loop logic
and the text.slice call in TodayTodoCard.tsx.

In `@apps/timo-web/app/today/page.tsx`:
- Around line 1-44: `TodayPage` is carrying client state and handlers, so move
the `useState` logic and `handleSubTodoCheck` out of `page.tsx` into a
client-only container such as `TodayContainer` under `_containers/`. Keep
`page.tsx` as a Server Component that only composes and renders the container,
and let `TodayContainer` own the `TodayTodoCard` wiring, `isDone`, `subTodos`,
and toggle handlers. Preserve the existing props and behavior by referencing
`TodayTodoCard`, `INITIAL_SUB_TODOS`, and `handleSubTodoCheck` in the new
container.

In `@apps/timo-web/components/CreateTodoToolbar.tsx`:
- Around line 36-52: The boolean props in CreateTodoToolbarProps are missing the
required is/has-style prefix, and delete is also a reserved word that forces
awkward renaming. Rename these flags in CreateTodoToolbarProps to prefixed
names, update the CreateTodoToolbar component’s prop destructuring to match, and
change the TodayTodoCard call site to pass the new prop names consistently. Keep
the API aligned with the boolean naming convention so the component interface is
clearer and avoids reserved-word handling.
- Around line 140-145: The tag control in CreateTodoToolbar currently renders an
empty TagIcon when tag is missing, leaving a blank chip visible. Update the tag
rendering logic around onTagClick and TagIcon so that when tag is absent it
either shows the same disabled state used by the other fields or is
conditionally not rendered at all, instead of passing an empty string as text.
Keep the behavior consistent with the existing activeItem-based rendering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d5709388-ffe9-4dc6-8864-4d0cc1f2e8c4

📥 Commits

Reviewing files that changed from the base of the PR and between f270c93 and 53cecbc.

⛔ Files ignored due to path filters (1)
  • packages/timo-design-system/src/icons/source/memo-blue.svg is excluded by !**/*.svg
📒 Files selected for processing (5)
  • apps/timo-web/app/today/_components/TodayTodoCard.tsx
  • apps/timo-web/app/today/page.tsx
  • apps/timo-web/components/.gitkeep
  • apps/timo-web/components/CreateTodoToolbar.tsx
  • packages/timo-design-system/src/components/tag/tag-icon/TagIcon.tsx

import { cn } from "@repo/timo-design-system/utils";
import { useEffect, useState } from "react";

import { CreateTodoToolbar } from "../../../components/CreateTodoToolbar";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e json 'tsconfig' apps/timo-web -x cat {}

Repository: Team-Timo/Timo-client

Length of output: 528


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== TodayTodoCard.tsx ==\n'
cat -n apps/timo-web/app/today/_components/TodayTodoCard.tsx | sed -n '1,80p'

printf '\n== CreateTodoToolbar files ==\n'
fd -a 'CreateTodoToolbar' apps/timo-web | sed -n '1,20p'

printf '\n== tsconfig paths ==\n'
cat -n apps/timo-web/tsconfig.json | sed -n '1,80p'

Repository: Team-Timo/Timo-client

Length of output: 3048


상대 경로 import를 별칭으로 바꿔주세요.

apps/timo-web/tsconfig.json@/*가 이미 잡혀 있어서 ../../../components/CreateTodoToolbar 대신 @/components/CreateTodoToolbar로 쓰면 경로 이동에 더 강해집니다.
관련 문서: Next.js Absolute Imports and Module Path Aliases

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/timo-web/app/today/_components/TodayTodoCard.tsx` at line 18, The import
in TodayTodoCard should use the existing `@/` alias instead of a brittle relative
path. Update the CreateTodoToolbar import in TodayTodoCard to reference the
alias form so it stays stable if the component moves, and keep the rest of the
component unchanged.

Source: Path instructions

Comment thread apps/timo-web/app/[locale]/(main)/today/_components/TodayTodoCard.tsx Outdated
Comment on lines +175 to +186
<div className="flex justify-end">
<CreateTodoToolbar
date={isDimmed ? undefined : toolbar?.date}
time={isDimmed ? undefined : toolbar?.time}
priority={isDimmed ? undefined : toolbar?.priority}
tag={isDimmed ? undefined : toolbar?.tag}
memo={!isDimmed && toolbar?.memo}
repeat={!isDimmed && toolbar?.repeat}
delete={!isDimmed}
onDeleteClick={onDelete}
/>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔵 Trivial

CreateTodoToolbar에 클릭 핸들러가 하나도 안 물려있어요 (delete 제외).

onDateClick/onTimeClick/onPriorityClick/onTagClick/onMemoClick/onRepeatClick이 전달되지 않아서, 버튼들은 시각적으로만 클릭 가능한 상태로 남아요(포커스는 되지만 아무 동작도 없음). 아직 상위 상태 연결 전 단계라면 의도된 것일 수 있지만, PR 목표에 명시되지 않은 부분이라 확인이 필요해 보여요.

향후 PR에서 처리될 예정이라면 무시하셔도 좋아요. 필요하시면 page.tsx(혹은 향후 _containers/)에서 해당 핸들러들을 연결하는 코드를 같이 만들어드릴까요?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/timo-web/app/today/_components/TodayTodoCard.tsx` around lines 175 -
186, CreateTodoToolbar is rendered with only the delete action wired, so the
other toolbar controls are visually clickable but do nothing. In TodayTodoCard,
pass through the missing handlers from the parent state/props for onDateClick,
onTimeClick, onPriorityClick, onTagClick, onMemoClick, and onRepeatClick
alongside the existing toolbar values, using the CreateTodoToolbar component as
the reference point.

Comment thread apps/timo-web/app/today/page.tsx Outdated
Comment thread apps/timo-web/components/CreateTodoToolbar.tsx
Comment thread apps/timo-web/components/CreateTodoToolbar.tsx
- app/today/_components에서 app/[locale]/(main)/today/_components로 이동했습니다
- CreateTodoToolbar import 경로를 새 위치에 맞게 수정했습니다
- truncateTitle 비교 연산자를 >= 에서 > 로 수정해 정확히 한국어 20자/영어 30자를 표시했습니다
- isDone 자동 정지 시 onPlay?.()를 호출해 부모 컴포넌트에 상태 변화를 알렸습니다
- CreateTodoToolbar 상대 경로 import를 @/components alias로 교체했습니다
- tag 값이 없을 때 빈 TagIcon 칩이 렌더링되던 버그를 수정했습니다

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CreateTodoToolbar에 isDimmed prop을 추가하여 dimmed 상태 아이콘을 Disable 변형으로 전환했습니다
- dimmed 상태에서 날짜·시간 텍스트 색상을 gray-700으로 변경했습니다
- toolbar 항목을 dimmed 상태에서 항상 표시하도록 변경했습니다
- isDraggable prop을 TodayTodoCard 및 TodayTodoCardContainer에서 제거했습니다
- handleCheck 시 서브투두를 일괄 완료 처리하도록 수정했습니다
@ehye1

ehye1 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

제가 수정했습니다.

  • TodayTodoListContainer 신규 생성 — todo 목록 렌더링 + 타이머 하나만 실행되도록 제약
  • page.tsx — 단일 카드 → 리스트 컨테이너로 교체
  • TodayTodoCard / TodayTodoCardContainer — isDraggable 제거, 완료 시 서브투두 일괄 체크
  • CreateTodoToolbar — isDimmed prop 추가, dimmed 상태일 때 아이콘 Disable 변형(+텍스트 색상 변경)
  • API 명세에 따라 mock 데이터 형태 변경

date, time, priority, memo, onDateClick, onTimeClick, onPriorityClick, onTagClick, onMemoClick에서 불필요한 ? 를 제거했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
type Priority를 type PriorityTypes로 변경했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
memo → hasMemo, repeat → hasRepeat, delete → hasDelete로 이름을 변경했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tag는 미설정 상태가 가능해 string | undefined이므로 ? 를 복구했습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TodayTodoCard에서 제공하지 않는 핸들러들을 다시 옵셔널로 되돌렸습니다.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment on lines +17 to +27
const formatDuration = (seconds: number): string => {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`;
};

const formatDate = (isoDate: string): string => {
const date = new Date(isoDate);
return `${date.getMonth() + 1}/${date.getDate()}`;
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 전체적으로 재사용될 가능성이 있어 보여서 공통 유틸로 빼줍시당

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TodayTodoListContainer의 formatDuration·formatDate 인라인 함수를 apps/timo-web/utils/로 분리했고, formatDuration은 focus/_utils/duration.ts와 동일해 convert-duration-to-time-text.ts로 통합했습니다!

@@ -0,0 +1,159 @@
"use client";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"use client";

ehye1 added 2 commits July 10, 2026 16:28
- TodayTodoListContainer의 formatDate·formatDuration 인라인 함수를 utils 폴더로 분리했습니다
- formatDuration은 기존 focus/_utils/duration.ts와 동일한 로직으로 convert-duration-to-time-text.ts로 통합했습니다
- FocusSessionContainer의 import 경로를 공유 유틸로 교체했습니다
- 서버 컴포넌트로 전환하여 불필요한 use client 디렉티브를 제거했습니다

@jjangminii jjangminii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

변경사항 많았을텐데 고생하셨습니다~
크리티컬은 아니지만 로직에 대해 간단한 코멘트 남겨뒀어요 확인해주세요-!

Comment on lines +46 to +63
const handleSubTodoCheck = (todoId: number, subtaskId: string) => {
// TODO: API
setTodos((prev) =>
prev.map((t) =>
t.todoId === todoId
? {
...t,
subtasks: t.subtasks.map((s) =>
s.subtaskId === Number(subtaskId)
? { ...s, completed: !s.completed }
: s,
),
}
: t,
),
);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subtaskId가 number → string → number로 왕복 변환되고 있는데, SubTodo.id를 number로 맞추면 변환 로직 자체를 없앨 수 있을 것 같아요-! 지금은 안전하지만 나중에 id 형식이 바뀌면 Number() 변환에서 조용히 실패할 수 있어서, 미리 타입을 통일해두면 어떨까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id: number로 통일하고 변환 로직을 제거했습니다!GOod

Comment on lines +20 to +23
const [todos, setTodos] = useState<TodoMock[]>(todayTodoMocks);
const [runningTodoId, setRunningTodoId] = useState<number | null>(
todayTodoMocks.find((t) => t.timerStatus === "RUNNING")?.todoId ?? null,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runningTodoId가 todos의 timerStatus와 별도 state로 관리되고 있어서, todo가 삭제/완료될 때마다 두 state를 수동으로 동기화해주고 계신 것 같아요! todos.find(t => t.timerStatus === "RUNNING")?.todoId로 파생시키면 동기화 코드 자체가 필요 없어질 것 같은데, 혹시 Zustand 연결 시점에 구조가 또 바뀔 예정이라 지금은 편의상 분리해두신 걸까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runningTodoId를 별도 state로 두면 삭제/완료 시마다 수동으로 동기화해야하네요,, todos에서 파생시키는 방식으로 수정했습니다! Zustand 연결 시점에도 timerStatus를 store에서 관리하면 동일하게 파생 가능할 것 같네요

@kimminna kimminna left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생했어요!

Comment on lines +1 to +26
interface TodoTag {
tagId: number;
name: string;
}

interface TodoSubtask {
subtaskId: number;
content: string;
completed: boolean;
}

export interface TodoMock {
todoId: number;
icon: string;
title: string;
completed: boolean;
date: string;
durationSeconds: number;
priority: "URGENT" | "HIGH" | "MEDIUM" | "LOW";
tag: TodoTag | null;
hasMemo: boolean;
isRepeated: boolean;
timerStatus: "RUNNING" | "PAUSED" | "STOPPED";
sortOrder: number;
subtasks: TodoSubtask[];
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인터페이스들 나중에 API 연동 시에는 zod 도입해 봅시다!

ehye1 added 2 commits July 11, 2026 02:20
- SubTodo.id를 string에서 number로 변경했습니다
- onSubTodoCheck 콜백의 id 파라미터 타입을 string에서 number로 변경했습니다
- runningTodoId를 별도 state에서 todos.find()로 파생되는 값으로 변경했습니다
- handlePlay에서 timerStatus를 todos 내부에서 관리하도록 수정했습니다
- handleCheck·handleDelete의 수동 동기화 코드를 제거했습니다
- subtaskId의 String()·Number() 왕복 변환을 제거했습니다

@yumin-kim2 yumin-kim2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셧써요 ❣️

- SubTodo.id 타입 변경에 따라 onSubTodoCheck id 파라미터를 string에서 number로 수정했습니다
@ehye1 ehye1 merged commit 190a031 into develop Jul 10, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능(기능성) 구현 ⌚ Timo-Design-system Timo 디자인 시스템 ⏰ Timo-web Timo 웹 서비스 ♥️ 혜원 혜원양

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 오늘 화면 TodayTodoCard 컴포넌트 구현

4 participants